#include "StdAfx.h"
#include "SilhouetteServer.h"


SOCKET ListeningSocket;
SOCKET ConnectionSocket = INVALID_SOCKET;
FD_SET read_fds;
timeval timeout;

// Constructor
SilhouetteServer::SilhouetteServer(void)
{
	// Fire up WinSock
	WSAData wsaData;
	int nCode;

    if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0) {
		printf("\nWSAStartup error %i\n", nCode);
    }
}


// Setup server to listen for incoming connections
void SilhouetteServer::setup(void) {
	// Start listening for connections
    ListeningSocket = SetUpListener(tcpHost, htons(tcpPort));
    if (ListeningSocket == INVALID_SOCKET) {
        printf("\nError establishing listener\n");
    }
}

// Deconstructor
SilhouetteServer::~SilhouetteServer(void)
{
	// Shut Winsock back down and take off.
    WSACleanup();
}



// Check's if a new connection is pending and if so, accepts it
void SilhouetteServer::WaitForConnection(void)
{
	sockaddr_in sinRemote;
	int nAddrSize = sizeof(sinRemote);

	ConnectionSocket = accept(ListeningSocket, (sockaddr*)&sinRemote, &nAddrSize);	
		cvNamedWindow("Broadcast", 1);

	// Set timeout to minimum
	timeout.tv_sec = 0;
	timeout.tv_usec = 1;

	FD_ZERO(&read_fds);

	// Bind
	FD_SET(ConnectionSocket, &read_fds);
}
	


// Transfers a silhouette to the client
bool SilhouetteServer::TransferImage(IplImage* image) 
{
	// Calculate buffer size
	int bufSize = 100 + image->width*image->height;
	char* strHeader = (char*) malloc(bufSize * sizeof(char));
	char* strOut;
	char space[2];
	char newline[2];
	int res = 0;
	

	sprintf(strHeader, "%i %i",image->width, image->height);

	sprintf(space, " ");
	strOut = strcat(strHeader, space);
	
	cvShowImage("Broadcast", image);

	// Dump pixel values
	int cnt = 0;

	for (int x=0; x < image->width; x++) {
		for (int y=0; y < image->height; y++) {
			// Calculate current position
			int pos = x + y*image->widthStep;
			

			// Append pixel value to string
			char pnt[2];
			if (image->imageData[pos] == 0){
				sprintf(pnt,"0");
			} else {
				sprintf(pnt,"1");
			}

			strOut = strcat(strOut, pnt);			
			cnt++;
		}
	}
	
	// attach \n
	sprintf(newline, "\n");
	strOut = strcat(strOut, newline);
	
	// Figure out, if client still connected
	res = send(ConnectionSocket, strOut, strlen(strOut),0);
	if (res == SOCKET_ERROR) {
		printf("[Server] Client not responding...\n", cnt);
		return false;
	}

	printf("[Server] %i pixels processed and send\n", cnt);
	return true;

}




//// SetUpListener /////////////////////////////////////////////////////
// Sets up a listener on the given interface and port, returning the
// listening socket if successful; if not, returns INVALID_SOCKET.

SOCKET SilhouetteServer::SetUpListener(const char* pcAddress, int nPort)
{
    u_long nInterfaceAddr = inet_addr(pcAddress);
    if (nInterfaceAddr != INADDR_NONE) {
        SOCKET sd = socket(AF_INET, SOCK_STREAM, 0);
        if (sd != INVALID_SOCKET) {
            sockaddr_in sinInterface;
            sinInterface.sin_family = AF_INET;
            sinInterface.sin_addr.s_addr = nInterfaceAddr;
            sinInterface.sin_port = nPort;
            if (bind(sd, (sockaddr*)&sinInterface, 
                    sizeof(sockaddr_in)) != SOCKET_ERROR) {
                listen(sd, 1);
                return sd;
            }
        }
    }

    return INVALID_SOCKET;
}

// Checks if the client requested a recalibration
bool SilhouetteServer::CheckRecalibration(void) {
	// Check if the client did send something
	FD_SET(ConnectionSocket, &read_fds);

	// Query	
	select(0, &read_fds, NULL, NULL, &timeout);

	// Check if recv buffer is non-empty
	if (FD_ISSET(ConnectionSocket, &read_fds)) {
		// Empty buffer
		int res = 0;
		char* c = (char*) malloc(2*sizeof(char));

		while (FD_ISSET(ConnectionSocket, &read_fds)) {
			// Read a little from the rcvr buffer
			res = recv(ConnectionSocket, c, 2, 0);

			// Check if connection is still alive
			if (res == SOCKET_ERROR)
				return false;

			// Update status
			select(0, &read_fds, NULL, NULL, &timeout);
		}
		free(c);
		return true;
	}
	return false;
}